<TITLE>FAT Filesystems</TITLE>

<H2>FAT filesystem</H2>

FAT stands for <I>File Allocation Table</I>, the main feature of this
 filesystem. The FAT filesystem is associated with DOS and some versions
 of Windows. <B><I>VFAT</I></B> (virtual FAT) is FAT with
 <B>long filenames</B>.
<P>
Newly-purchased floppy disks advertised as 'formatted' usually contain
 a FAT12 filesystem.

<H3>Layout of a FAT volume</H3>

<img src="fat-2.html"><br>
A FAT volume contains:
<UL>
<LI>boot sector (more than one for FAT32)
<LI>one or more copies of the FAT (almost always 2 copies)
<LI>root directory (not present for FAT32)
<LI>the data area, where files and subdirectories are stored. For FAT32,
 the root directory is also stored here.
</UL>

<H3>FAT bootsector and BPB</H3>

The FAT boot sector contains:
<UL>
<LI>Code to load and run the DOS kernel
<LI>The poorly-named <I><B>BIOS Parameter Block</B></I> (BPB), with disk
 geometry and filesystem info. The BPB corresponds to the <I>superblock</I>
 of UNIX filesystems.
<LI>Magic values: 55h at offset 510, 0AAh at offset 511.
</UL>

Layout of FAT12/FAT16 bootsector with <B>minimal BPB</B>:

<PRE>typedef unsigned char	uint8_t;	/* or #include &lt;stdint.h&gt; */
typedef unsigned short	uint16_t;	/* Note: multi-byte values are little-endian */
typedef unsigned long	uint32_t;
struct fat_bootsector			/* Warning: this struct must be packed */
{
        uint8_t  jump[3];               /* 16-bit JMP to boot code, or 8-bit JMP + NOP */
        uint8_t  oem_id[8];             /* e.g. 'MSWIN4.0' */
	uint16_t bytes_per_sector;	/* usu. =512 */
        uint8_t  sectors_per_cluster;
	uint16_t num_boot_sectors;	/* usu. =1 */
        uint8_t  num_fats;              /* usu. =2 */
	uint16_t num_root_dir_ents;
	uint16_t total_sectors;		/* 16-bit; 0 if num sectors > 65535 */
        uint8_t  media_ID_byte;         /* usu. =0F0h */
	uint16_t sectors_per_fat;
	uint16_t sectors_per_track;
	uint16_t heads;
	uint32_t hidden_sectors;	/* =LBA partition start */
	uint32_t total_sectors_large;	/* 32-bit; 0 if num sectors < 65536 */
        uint8_t  boot_code[474];
        uint8_t  magic[2];              /* 55h, 0AAh */
};                              /* 512 bytes total */</PRE>

<H3>FAT directory entries</H3>

FAT directory entries are 32 bytes long:

<PRE>typedef unsigned char	uint8_t;	/* or #include &lt;stdint.h&gt; */
typedef unsigned short	uint16_t;	/* Note: multi-byte values are little-endian */
typedef unsigned long	uint32_t;
struct fat_dirent               	/* Warning: this struct must be packed */
{
        uint8_t  name[8];               /* ALL-CAPS, pad right with spaces */
        uint8_t  ext[3];                /* ALL-CAPS, pad right with spaces */
        uint8_t  attrib;                /* attribute byte */
        uint8_t  reserved;              /* =0 */
        uint8_t  ctime_ms;              /* file creation time, 10ms units */
	uint16_t ctime;              	/* file creation time, in DOS format */
	uint16_t cdate;              	/* file creation date, in DOS format */
	uint16_t adate;              	/* DOS date of last file access */
	uint16_t st_clust_msw;       	/* high 16 bits of starting cluster (FAT32) */
	uint16_t mtime;              	/* DOS time of last file modification */
	uint16_t mdate;              	/* DOS date of last file modification */
	uint16_t st_clust;           	/* starting cluster */
	uint32_t file_size;          	/* in bytes */
};                              /* 32 bytes total */</PRE>

DOS times and dates are stored in these formats:
<PRE>struct dos_time                 /* Warning: this struct must be packed */
{
	unsigned two_secs : 5;  /* low 5 bits: 2-second increments */
	unsigned minutes : 6;   /* middle 6 bits: minutes */
	unsigned hours : 5;     /* high 5 bits: hours (0-23) */
};                              /* 2 bytes total */

struct dos_date                 /* Warning: this struct must be packed */
{
	unsigned date : 5;      /* low 5 bits: date (1-31) */
	unsigned month : 4;     /* middle 4 bits: month (1-12) */
	unsigned year : 7;      /* high 7 bits: year - 1980 */
};                              /* 2 bytes total */</PRE>

The Attribute byte is similar to the file 'mode' under UNIX filesystems:

<PRE>struct attrib                   /* Warning: this struct must be packed */
{
	int read_only : 1;      /* b0 */
	int hidden : 1;
	int system : 1;
	int volume_label : 1;
	int directory : 1;
	int archive : 1;
	int reserved : 2;       /* b6, b7 */
};                              /* 1 byte total */</PRE>

FAT directory entries contain all <I>metadata</I> for a particular file.
 This is different from UNIX filesystems, which store metadata separately
 from the directory entries (in <I>inodes</I>). FAT directory entries are
 also used for disk volume labels and VFAT long filenames.

<H3>The FAT</H3>

Entries in the FAT can be 12 bits wide (FAT12), 16 bits wide (FAT16), or
 32 bits wide (FAT32). FAT entries do not necessarily refer to disk
 sectors, but to <B><I>clusters</I></B>, which are <B>groups of contiguous
 sectors</B>. The number of sectors per cluster is always a power of 2.
 The FAT format used is determined solely by the number of clusters in the
 volume:
<UL>
<LI>FAT12: 1...4084 (0FF4h) clusters
<LI>FAT16: 4085...65524 (0FFF4h) clusters
<LI>FAT32: 65525... clusters
</UL>

Used FAT entries form <B>singly linked lists</B>, indicating which clusters
 are used by each file or subdirectory. Some FAT entry values are special:

<TABLE WIDTH="100%" BORDER><TR>
 <TH>Meaning  of FAT entry value</TH>             <TH>FAT12</TH>
	<TH>FAT16</TH>                  <TH>FAT32</TH>
</TR><TR>
 <TD>Free cluster</TD>                  <TD>0</TD>
	<TD>0</TD>                      <TD>0</TD>
</TR><TR>
 <TD>Used cluster; pointer to next</TD> <TD>2-0FF5h</TD>
	<TD>2-0FFF5h</TD>               <TD>2-0FFFFFF5h <B>(28-bit)</B></TD>
</TR><TR>
 <TD>Reserved</TD>                   <TD>0FF6h</TD>  <TD>0FFF6h</TD>
	<TD>0FFFFFF6h <B>(28-bit)</B></TD>
</TR><TR>
 <TD>Bad cluster</TD>                   <TD>0FF7h</TD>  <TD>0FFF7h</TD>
	<TD>0FFFFFF7h <B>(28-bit)</B></TD>
</TR><TR>
 <TD>Reserved</TD>                   <TD>0FF8h-0FFEh</TD>  <TD>0FFF8h-0FFFEh</TD>
	<TD>0FFFFFF8h-0FFFFFFEh<B>(28-bit)</B></TD>
</TR><TR>
 <TD>Used cluster; last in chain</TD>   <TD>0FFFh</TD>  <TD>0FFFFh</TD>
	<TD>0FFFFFFFh <B>(28-bit)</B></TD>
</TR></TABLE>
<P>
Example: maximum hard disk partition size for FAT16 with 64 sectors/cluster
 = 65524 clusters * 512-byte sectors * 64 sectors/cluster = 2047 Mbytes.
<P>
Example: <I>DMF</I> floppy disk format, used by Win95 install flopies.
 These floppies have 21 sectors/track instead of 18, so they hold 1.68 Mbytes
 and have 3360 sectors. This is below the 4085-cluster FAT12 limit, however,
 DMF disks have 4 sectors/cluster. This reduces the size of the FATs which,
 along with a smaller root directory, leaves more room for data.